package com.gptompay_plugin.gptompay_plugin


// Kotlin协程相关
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.IBinder
import android.util.Log
import androidx.annotation.NonNull
import cn.nexgo.smartconnect.ISmartconnectService
import cn.nexgo.smartconnect.listener.IInquireResultListener
import cn.nexgo.smartconnect.listener.IStateResultListener
import cn.nexgo.smartconnect.listener.ITransactionRegisterListener
import cn.nexgo.smartconnect.listener.ITransactionResultListener
import cn.nexgo.smartconnect.model.ClientInfoEntity
import cn.nexgo.smartconnect.model.InquireResultEntity
import cn.nexgo.smartconnect.model.ReceiptType
import cn.nexgo.smartconnect.model.RegisterEntity
import cn.nexgo.smartconnect.model.RegisterResultEntity
import cn.nexgo.smartconnect.model.TransactionRequestRedirectInfoEntity
import cn.nexgo.smartconnect.model.TransactionRequestV2Entity
import cn.nexgo.smartconnect.model.TransactionResultEntity
import cn.nexgo.smartconnect.model.UserContactEntity
import com.google.gson.Gson
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import io.flutter.plugin.common.MethodChannel.Result

/** GPtomPayPlugin */
class GPtomPayPlugin : FlutterPlugin, ActivityAware, MethodCallHandler {
    /// The MethodChannel that will the communication between Flutter and native Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private lateinit var channel: MethodChannel
//    private var activity: Activity? = null
    private lateinit var mContext: Context
    private val LOGGER_TAG: String = "GPTOMPayPlugin"
    private  val LOGGER_TAG_REQUEST: String = "REQUEST_LOG_REQUEST"
    private  val LOGGER_TAG_RESPONSE: String = "REQUEST_LOG_RESPONSE"

    private lateinit var iSmartconnectService: ISmartconnectService
    private var TOM_PACKAGE_NAME = ""
    private var TOM_SERVICE_NAME = "com.globalpayments.atom.data.external.api.NexgoAPIService"

    private  var connection : MyConnection? =null

    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "gptompay_plugin")
        channel.setMethodCallHandler(this)
    }

    override fun onMethodCall(@NonNull call: MethodCall, @NonNull callback: Result) {
        when (call.method) {
            ChannelConfig.BIND_SERVER -> {
                var packageName = call.argument<String>("packageName") ?: "";
                TOM_PACKAGE_NAME = packageName
                var result = bindService()
                callback.success(result)
            }

            ChannelConfig.UNBIND_SERVER -> {
                var result = unbindService()
                callback.success(result)
            }

            ChannelConfig.REGISTER_V2 -> {
                val clientId = call.argument<String>("clientId")
                CoroutineScope(Dispatchers.Main).launch {
                    try {
                        val result = registerV2(clientId)
                        callback.success(result)
                    } catch (e: Exception) {
                        callback.error(ChannelConfig.REGISTER_V2, e.message, null)
                        Log.e(LOGGER_TAG_REQUEST, "registerV2=${e.message}")
                    }
                }
            }

            ChannelConfig.START_TRANS_V2 -> {
                try {
                    val amount = (call.argument<Number?>("amount")?.toLong())// ?: throw IllegalArgumentException("Amount is required")
                    val cancelMode = call.argument<Int?>("cancelMode")
                    val clientId = call.argument<String>("clientId") ?: throw IllegalArgumentException("Client ID is required")
                    val originReferenceNum = call.argument<String>("originReferenceNum") ?: throw IllegalArgumentException("Origin reference number is required")
                    val originTransactionID = call.argument<String>("originTransactionID") ?: throw IllegalArgumentException("Origin transaction ID is required")
                    val printByPaymentApp = call.argument<Boolean>("printByPaymentApp") ?: false
                    val tipAmount = call.argument<Number?>("tipAmount")?.toLong()// ?: 0L
                    val transactionID = call.argument<String>("transactionID") ?: throw IllegalArgumentException("Transaction ID is required")
                    val transactionType = call.argument<Int>("transactionType") ?: throw IllegalArgumentException("Transaction type is required")
                    val email = call.argument<String>("email") ?: ""
                    val phone = call.argument<String>("phone") ?: ""
                    val preferableReceiptType = call.argument<String>("preferableReceiptType") ?: "QR"
                    val tipCollect = call.argument<Boolean>("tipCollect") ?: false
                    val currencyCode = call.argument<String>("currencyCode") ?: ""

                    val redirectPackageName = call.argument<String>("redirectPackageName") ?: ""
                    CoroutineScope(Dispatchers.Main).launch {
                        try {
                            val result = startTransV2(
                                amount = amount,
                                cancelMode = cancelMode,
                                clientId = clientId,
                                originReferenceNum = originReferenceNum,
                                originTransactionID = originTransactionID,
                                printByPaymentApp = printByPaymentApp,
                                tipAmount = tipAmount,
                                transactionID = transactionID,
                                transactionType = transactionType,
                                email = email,
                                phone = phone,
                                preferableReceiptType = preferableReceiptType,
                                tipCollect = tipCollect,
                                currencyCode= currencyCode,
                                redirectPackageName =redirectPackageName
                            )
                            callback.success(result)
                        } catch (e: Exception) {
                            callback.success(null)
                            Log.e(LOGGER_TAG_REQUEST, "startTransV2=${e.message}")
                        }
                    }
                } catch (e: IllegalArgumentException) {
                    callback.error(ChannelConfig.START_TRANS_V2, e.message, null)
                    Log.e(LOGGER_TAG_REQUEST, "startTransV2=${e.message}")
                } catch (e: Exception) {
                    callback.error(ChannelConfig.START_TRANS_V2, e.message, null)
                    Log.e(LOGGER_TAG_REQUEST, "startTransV2=${e.message}")
                }
            }

            ChannelConfig.STATE -> {
                val transactionId = call.argument<String>("transactionId")
                CoroutineScope(Dispatchers.Main).launch {
                    try {
                        val result = getState(transactionId)
                        callback.success(result)
                    } catch (e: Exception) {
                        callback.error(ChannelConfig.STATE, e.message, null)
                        Log.e(LOGGER_TAG_REQUEST, "state=${e.message}")
                    }
                }
            }

            ChannelConfig.GET_TRANSACTON_DETAIL -> {
                val transactionId = call.argument<String>("transactionId")
                CoroutineScope(Dispatchers.Main).launch {
                    try {
                        val result = getTransactionDetail(transactionId)
                        callback.success(result)
                    } catch (e: Exception) {
                        callback.error(ChannelConfig.STATE, e.message, null)
                        Log.e(LOGGER_TAG_REQUEST, "getTransactionDetail=${e.message}")
                    }
                }
            }
        }
    }

    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
//        activity = binding.activity
        mContext = binding.activity
    }

    override fun onDetachedFromActivityForConfigChanges() {
        //the Activity your plugin was attached to was
        // destroyed to change configuration.
        // This call will be followed by onReattachedToActivityForConfigChanges().
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        //your plugin is now attached to a new Activity
        // after a configuration change.
    }

    override fun onDetachedFromActivity() {
        //your plugin is no longer associated with an Activity.
    }
    ///检查package
    private fun checkApplicationInstalled(): PackageInfo? {
        return try {
            mContext.packageManager?.getPackageInfo(TOM_PACKAGE_NAME, 0)
        } catch (e: PackageManager.NameNotFoundException) {
            null
        }
    }
    private fun createIntent() = Intent().apply {
        component = ComponentName(TOM_PACKAGE_NAME, TOM_SERVICE_NAME)
    }
    ///绑定服务
    private fun bindService() : String?{
        try {
            Log.d(LOGGER_TAG, "bindService")
            val connection = MyConnection()
            var packageInfo = checkApplicationInstalled()
            val intent = createIntent()

            if (mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE) != true) {
                throw IllegalStateException("Bind is unsuccessful")
            }
            var _map =  mapOf(
                "packageName" to packageInfo?.packageName,
                "versionName" to packageInfo?.versionName,
            )
            this.connection = connection;
            return Gson().toJson(_map)
        } catch (e: PackageManager.NameNotFoundException) {
            Log.e(LOGGER_TAG,"Application  is not installed.")
            return null;
        } catch (e: Exception) {
            Log.e(LOGGER_TAG,"Unable to bind to service: ${e.message}")
            return null;
        }
    }
    ///卸载绑定
    private fun unbindService() :Boolean {
        try {
            Log.d(LOGGER_TAG, "unbindService")
            this.connection?.let {
                mContext.unbindService(it)
            }
            this.connection = null
            return true
        } catch (e: Exception) {
            Log.e(LOGGER_TAG, "bind service exception: ${e.message}")
            return false
        }
    }

    ///注册交易
    private suspend fun registerV2(clientId: String?): String = suspendCancellableCoroutine { continuation ->
        try {
            val entity = RegisterEntity().apply {
                if (!clientId.isNullOrEmpty()) this.clientID = clientId
            }
            val requestJson = Gson().toJson(entity)
            Log.d(LOGGER_TAG_REQUEST, "registerV2=$requestJson")

            // 使用回调监听器
            val listener = object : ITransactionRegisterListener.Stub() {
                override fun onRegisterV2Result(result: String) {
                    Log.d(LOGGER_TAG_RESPONSE, "onRegisterV2Result=${result}");
                    continuation.resume(result) // 返回结果
                }
                override fun onRegisterResult(registerResultEntity: RegisterResultEntity) {
                    // 处理 V1 情况（如果有需要）
                }
            }
            iSmartconnectService.transactionRegisterV2(requestJson, listener)
        } catch (e: Exception) {
            continuation.resumeWithException(e) // 抛出异常
        }
    }
    ///开始交易
    /*
    amount 金额
    cancelMode
    clientId
    originReferenceNum 原始交易编号
    originTransactionID 原始交易id
    printByPaymentApp 是否在app中打印
    tipAmount 小费金额
    transactionID 交易id
    transactionType 交易类型
    preferableReceiptType 首选收据类型
    tipCollect 收集小费
    currencyCode 货币代码
     */
    private suspend fun startTransV2(
        amount:Long?,
        cancelMode:Int?,
        clientId:String,
        originReferenceNum:String,
        originTransactionID:String,
        printByPaymentApp: Boolean,
        tipAmount: Long?,
        transactionID:String,
        transactionType:Int,
        email:String,
        phone:String,
        preferableReceiptType: String,
        tipCollect: Boolean,
        currencyCode:String,
        redirectPackageName:String,
    ): String = suspendCancellableCoroutine { continuation ->
       try {
           val entity = TransactionRequestV2Entity().apply {
               if(amount!=null){
                   this.amount = amount;
               }
               if (cancelMode!=null) this.cancelMode =cancelMode
               if(originReferenceNum.isNotEmpty()) this.originReferenceNum = originReferenceNum
               if(originTransactionID.isNotEmpty()) this.originTransactionID = originTransactionID
               this.printByPaymentApp = printByPaymentApp
               if(tipAmount!=null){
                   this.tipAmount = tipAmount
               }
               this.transactionID = transactionID
               this.transactionType = transactionType
               this.preferableReceiptType = ReceiptType.valueOf(preferableReceiptType)
               this.tipCollect = tipCollect
               if(currencyCode.isNotEmpty()){
                   this.currencyCode = currencyCode
               }
               if (clientId.isNotEmpty()) this.clientID = clientId
           }
           var  clientInfo =  ClientInfoEntity();

           var clientContact = UserContactEntity()
           clientContact.phone = phone;
           clientContact.email = email;
           clientInfo.setContact(clientContact);
           entity.clientInfo = clientInfo
           if(redirectPackageName.isNotEmpty()){
               var redirectInfo = TransactionRequestRedirectInfoEntity();
               redirectInfo.packageName = redirectPackageName
               entity.redirectInfo = redirectInfo
           }

           val requestJson = Gson().toJson(entity)
           Log.d(LOGGER_TAG_REQUEST, "startTransV2=$requestJson")

           // 使用回调监听器
           val listener = object : ITransactionResultListener.Stub() {
               override fun onTransactionV2Result(result: String) {
                   Log.d(LOGGER_TAG_RESPONSE, "onTransactionV2Result=${result}");
                   continuation.resume(result) // 返回结果
               }
               override fun onTransactionResult(transactionResultEntity: TransactionResultEntity) {
                   // 处理 V1 情况（如果有需要）
               }
           }
           iSmartconnectService.transactionRequestV2(requestJson, listener)
       } catch (e: Exception) {
           continuation.resumeWithException(e) // 抛出异常
       }
    }
    ///获取交易状态
    private suspend fun getState(transactionId: String?): String = suspendCancellableCoroutine { continuation ->
        try {
            Log.d(LOGGER_TAG_REQUEST, "state=$transactionId")
            // 使用回调监听器
            val listener = object : IStateResultListener.Stub() {
                override fun onStateResult(result: String) {
                    Log.d(LOGGER_TAG_RESPONSE, "onStateResult=${result}");
                    continuation.resume(result) // 返回结果
                }
            }
            iSmartconnectService.stateRequest(transactionId, listener)
        } catch (e: Exception) {
            continuation.resumeWithException(e) // 抛出异常
        }
    }
    ///获取交易详情
    ///获取交易状态
    private suspend fun getTransactionDetail(transactionId: String?): String = suspendCancellableCoroutine { continuation ->
        try {
            Log.d(LOGGER_TAG_REQUEST, "state=$transactionId")
            // 使用回调监听器
            val listener = object : IInquireResultListener.Stub() {
                override fun onInquireResult(inquireResultEntity: InquireResultEntity) {
                    val result: String = Gson().toJson(inquireResultEntity)
                    Log.d(LOGGER_TAG_RESPONSE, "onInquireResult=${result}");
                    continuation.resume(result) // 返回结果
                }
            }
            iSmartconnectService.TransactionInquire(transactionId, listener)
        } catch (e: Exception) {
            continuation.resumeWithException(e) // 抛出异常
        }
    }
    inner class MyConnection : ServiceConnection {
        var isConnected: Boolean = false
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            Log.d(LOGGER_TAG, "service CONNECTED")
            iSmartconnectService = ISmartconnectService.Stub.asInterface(service)
            isConnected = true
        }

        override fun onServiceDisconnected(name: ComponentName) {
            Log.d(LOGGER_TAG, "service DISCONNECTED")
            isConnected = false
        }
    }
}
